#include "BigInteger.h"

#ifdef _MINI_CRYPT


using namespace std;
using namespace WONCryptMini;

bool BigInteger::debugStr = false;

const BigInteger BigInteger::ZERO = BigInteger(0);
const BigInteger BigInteger::ONE = BigInteger(1);

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

void BigInteger::debugInitStr() const
{
	if(debugStr)
		initStr();
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

void BigInteger::initStr() const
{
#ifdef BIGINT_DEBUG_STR
	mVal = toString();
#endif
}


      
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger::BigInteger()
{
	debugInitStr();
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger::BigInteger(const BigInteger &theVal)
{
	copy(*this,theVal);
	debugInitStr();
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

const BigInteger& BigInteger::operator =(const BigInteger& theVal)
{
	copy(*this,theVal);

	debugInitStr();
	return *this;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/*
BigInteger::BigInteger(unsigned int from)
{
    assign(from);
	debugInitStr();
}*/

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger::BigInteger(__int64 theFrom, bool negative)
{
	RawBuffer aBuf;
	unsigned __int64 from;

	if(negative) 
		from = -theFrom;
	else
		from = theFrom;

	unsigned char *start = ((unsigned char*)&from) + 7;

	for(int i=0; i<8; i++)
	{
		aBuf+=*start;

		start--;
	}

	fromBinary(aBuf);

	this->negative = negative;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger::BigInteger(const string &theString)
{
    fromString(theString);
	debugInitStr();
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger::BigInteger(const RawBuffer &buffer)
{
    fromByteArray(buffer);
	debugInitStr();
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger::BigInteger(int numBits, Random &rndSrc)
{
	fromByteArray(randomBits(numBits,rndSrc));
	debugInitStr();
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

RawBuffer BigInteger::randomBits(int numBits, Random &rndSrc)
{		
	int numBytes = (numBits+7)/8;
	RawBuffer randomBits(numBytes,0);

	// Generate random bytes and mask out any excess bits 
	if (numBytes > 0) 
	{
		rndSrc.nextBytes(randomBits);
		int excessBits = 8*numBytes - numBits;
		randomBits[0] &= (1 << (8-excessBits)) - 1;
	}
	return randomBits;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

bool BigInteger::testBit(int theBit)
{
	return bit(*this,theBit);
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger& BigInteger::setBit(int theBit)
{
	BigNum::setBit(*this,theBit);
	return *this;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::gcd(const BigInteger &b) const
{
	BigInteger r;
	BigNum::gcd(r,*this,b);

	return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

int BigInteger::bitLength() const
{ 
	return BigNum::bitLength(*this); 
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

void BigInteger::fromString(const std::string& theString)
{

	BigNum::zero(*this);

	int aPos = 0;
	while(aPos<theString.length() && isspace(theString[aPos]))
		aPos++;

	int lastPos = aPos;
	while(lastPos<theString.length() && isdigit(theString[lastPos]))
		lastPos++;

	string aStr = theString.substr(aPos,lastPos-aPos);


	BigInteger thousand(1000);
	BigInteger r1(0), r2(0);

	if(aStr.size()%3!=0)
	{
		string aSubStr = aStr.substr(0,aStr.size()%3);
		r1 = r2 = atoi(aSubStr.c_str());
		aPos+=aStr.size()%3;
	}
	
	while(aPos<aStr.length())
	{
		string aSubStr = theString.substr(aPos,3);

		
		BigInteger anInt = atoi(aSubStr.c_str());

		BigNum::mul(r1,thousand,r2);
		BigNum::add(r1,r1,anInt);

		r2 = r1;
		aPos+=3;
	}

	copy(*this,r1);
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

static char IntToHex(int theDigit)
{
	if(theDigit<=9)
		return '0' + theDigit;
	else
		return 'A' + (theDigit - 10);
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

std::string BigInteger::toString() const
{
	bool origDebug = debugStr;

	debugStr = false;

	string s;

	BigInteger N(1000);
	BigInteger r;
	BigInteger tmp = *this;

	char aBuf[20];

	while(!tmp.equals(BigInteger::ZERO))
	{
		tmp = tmp.divrem(N,r);
		sprintf(aBuf,"%03d",r.n[0]);
		s=aBuf+s;
	}

	debugStr = origDebug;


/*
    RawBuffer buffer = toByteArray();

	for(int i=buffer.length()-1; i>=0; i--)
	{
		int low = buffer[i] & 0x0f;
		int high = (buffer[i] & 0xf0) >> 4;
	
		s+=IntToHex(high);
		s+=IntToHex(low);
	}*/

    // remove leading 0's.
    int pos = 0, len = s.length();
    while ((pos < len) && (s[pos] == '0'))
        pos++;

    if (pos == len) 
	{
        return "0";
    }
	else 
	{	
        return s.substr(pos);
    }		
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::modExp(const BigInteger &power, const BigInteger &modulo) const
{
	BigInteger r;
	BigNum::modExp(r, *this, power, modulo);

	r.debugInitStr();
    return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::modExp(const BigInteger &power, const BigInteger &modulo, const BigInteger &recip, short nb) const
{
	BigInteger r;
	BigNum::modExp(r, *this, power, modulo,recip,nb);

	r.debugInitStr();
    return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::inverseModN(const BigInteger &n) const
{
	BigInteger r;

	BigNum::inverseModN(r,*this, n);

	r.debugInitStr();
    return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::mod(const BigInteger &b) const
{
	BigInteger r;

	BigNum::mod(r, *this, b);
   
	r.debugInitStr();	
	return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::mul(const BigInteger &b) const
{
	BigInteger r;
	BigNum::mul(r, *this, b);

	r.debugInitStr();
    return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::div(const BigInteger &b) const
{
	BigInteger r;
	
	BigNum::div(r, *this, b);

    r.debugInitStr();
	return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::divrem(const BigInteger &a, BigInteger &rem) const
{
	BigInteger div;
	BigNum::div(&div,&rem,*this,a);

	return div;
}


///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::add(const BigInteger &b) const
{
	BigInteger r;
	
	BigNum::add(r, *this, b);
    return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::sub(const BigInteger &b) const
{
	BigInteger r;
	BigNum::sub(r, *this, b);

	r.debugInitStr();
    return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

int BigInteger::cmp(const BigInteger &a) const
{
    return BigNum::cmp(*this, a);
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger& BigInteger::shiftLeft(int n)
{
	BigNum::shiftLeft(*this, *this, (short) n);
    return *this;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger& BigInteger::shiftRight(int n)
{
	BigNum::shiftRight(*this, *this, (short) n);
    return *this;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

RawBuffer BigInteger::toByteArray() const
{
    RawBuffer buffer(bitLength(),' ');
    intoBinary(buffer);
    return buffer;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

void BigInteger::fromByteArray(const RawBuffer &buf)
{
    fromBinary(buf);
	debugInitStr();
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

bool BigInteger::equals(const BigInteger &b) const
{
    return (cmp(b) == 0);
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::recip(int &nb) const
{
	BigInteger r;

	nb = BigNum::recip(r,*this);
	return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::modMulRecip(const BigInteger &y, const BigInteger &m, const BigInteger &i, short nb) const
{
	BigInteger r;

	BigNum::modMulRecip(r,*this,y,m,i,nb);
	
	return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::exp(const BigInteger &power) const
{
	BigInteger r;

	BigNum::exp(r,*this,power);

	return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

unsigned __int64 BigInteger::GetInt64() const
{
	BigInteger r;
	unsigned __int64 aVal = 0;

	RawBuffer aBuf = toByteArray();
	for(int i=0; i<aBuf.length(); i++)
	{
		aVal = (aVal<<8)|aBuf[i];
	}

	return aVal;


}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::negate() const
{
	BigInteger r(*this);

	r.negative = !(this->negative);
	return r;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

bool BigInteger::operator<(const BigInteger &a) const
{
	return cmp(a)<0;
}


///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

std::ostream& WONCryptMini::operator<<(std::ostream &os,const BigInteger &theNum)
{
	os << theNum.toString();
	return os;
}
 
/*
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

BigInteger BigInteger::sqrt() const
{
	BigInteger r;

	BigNum::sqrt(r,*this);

	return r;
}
*/

#endif
